

namespace Stee.CAP8.MessageBus.Interface.Interfaces
{
    using System;
    using System.Collections.Generic;
    using System.Threading;
    using System.Threading.Tasks;
    using Stee.CAP8.MessageBus.Interface.Delegates;
    using Stee.CAP8.MessageBus.Interface.Models;

    /// <summary>
    /// Publisher interface
    /// 
    /// RabbitMQ
    ///     Fanout exchange, sends to all regardless or routing key or patterns
    ///     Direct exchange, uses the routing key to publish ("exchange-name")
    ///     Topic exchange, matches the routing key with a routing pattern ("*.service.incident")
    ///     Header exchange, uses the message arguments ("key1: value1", "key2.value2", "x-match: any/all")
    /// 
    /// Kafka
    ///     Uses topic name & application group ID
    /// </summary>
    public interface IPublisher : IDisposable
    {
        #region Properties

        /// <summary>
        /// Gets the flag indicating that publisher is initialized and ready for publishing
        /// </summary>
        bool IsInitialized { get; }

        /// <summary>
        /// Gets the flag indicating disposed state
        /// </summary>
        bool IsDisposed { get; }

        #endregion Properties


        /// <summary>
        /// Initializes the publisher
        /// </summary>
        /// <param name="publishResponseHandler">Publish response handler, response data type</param>
        /// <param name="brokerErrorHandler">Error handler</param>
        /// <returns>Return TRUE if initialized else FALSE</returns>
        bool Initialize(HandlePublishResponse publishResponseHandler, HandleBrokerError brokerErrorHandler);


        #region Generic

        /// <summary>
        /// Publish message
        /// </summary>
        /// <typeparam name="TMessage">Message data type</typeparam>
        /// <param name="topicName">Message topic</param>
        /// <param name="message">Serializable message</param>
        /// <returns>Return TRUE if published successfully else FALSE</returns>
        bool Publish<TMessage>(TopicName topicName, TMessage message, CancellationToken cancelToken);

        /// <summary>
        /// Publish message asynchronously
        /// </summary>
        /// <typeparam name="TMessage">Message data type</typeparam>
        /// <param name="topicName">Message topic</param>
        /// <param name="message">Serializable message</param>
        /// <param name="cancelToken">Cancel token</param>
        /// <returns>Return TRUE if published successfully else FALSE</returns>
        Task<bool> PublishAsync<TMessage>(TopicName topicName, TMessage message, CancellationToken cancelToken);

        /// <summary>
        /// Publish message with additional properties
        /// </summary>
        /// <typeparam name="TMessage">Message data type</typeparam>
        /// <param name="topicName">Message topic</param>
        /// <param name="message">Serializable message</param>
        /// <param name="properties">Meta-data for message</param>
        /// <param name="cancelToken">Cancel token</param>
        /// <returns>Return TRUE if published successfully else FALSE</returns>
        bool Publish<TMessage>(TopicName topicName, TMessage message, IDictionary<string, object> properties, CancellationToken cancelToken);

        /// <summary>
        /// Publish message with additional properties asynchronously
        /// </summary>
        /// <typeparam name="TMessage">Message data type</typeparam>
        /// <param name="topicName">Message topic</param>
        /// <param name="message">Serializable message</param>
        /// <param name="properties">Meta-data for message</param>
        /// <param name="cancelToken">Cancel token</param>
        /// <returns>Return TRUE if published successfully else FALSE</returns>
        Task<bool> PublishAsync<TMessage>(TopicName topicName, TMessage message, IDictionary<string, object> properties, CancellationToken cancelToken);

        #endregion Generic


        #region Commands

        /// <summary>
        /// Publish message
        /// </summary>
        /// <param name="topicName">Message topic</param>
        /// <param name="commandMsg">Command message</param>
        /// <param name="cancelToken">Cancel token</param>
        /// <returns>Return TRUE if published successfully else FALSE</returns>
        bool PublishCommand(TopicName topicName, CommandMessage commandMsg, CancellationToken cancelToken);

        /// <summary>
        /// Publish command message asynchronously
        /// </summary>
        /// <param name="topicName">Message topic</param>
        /// <param name="commandMsg">Command message</param>
        /// <param name="cancelToken">Cancel token</param>
        /// <returns>Return TRUE if published successfully else FALSE</returns>
        Task<bool> PublicCommandAsync(TopicName topicName, CommandMessage commandMsg, CancellationToken cancelToken);

        #endregion Commands


        #region Events
        #endregion Events
    }
}
